use fn_method::method_mod::Circle;
use fn_method::method_mod::method_test;

pub fn invoke() {
//    deverges_test();
    closure_test();
    high_order_function();
    method_test();
}
fn deverges() -> ! {
    panic!("This function never returns !");
}

fn deverges_test() {
    let x: i32 = deverges();
    let y: String = deverges();
    println!("the value of x is {}", x);
    println!("the value of y is {}", y);
}

//匿名函数 Rust使用闭包 (closure) 来创建匿名函数：
fn closure_test() {
    let num = 5;
    let plus_num = |x: i32| x + num;
    println!("闭包函数调用后的结果值为：{}" , plus_num(10));
    println!("{}" , num);

    let mut num = 5;
    {
        // 闭包通过move获取了num的所有权
        let mut add_num = move |x: i32| num += x;
        add_num(5);
    }
    // 下面的num在被move之后还能继续使用是因为其实现了Copy特性
    assert_eq!(5, num);
}

//高阶函数
fn high_order_function() {
    fn add_one(x: i32) -> i32 {x + 1}
    fn apply<F>(f: F, y: i32) -> i32 where F: Fn(i32) -> i32{
        f(y) * y
    }

    //创建一个本地变量transform来存放闭包执行的结果，这样闭包就只会执行一次，所以有如下结果
    let transform: fn(i32) -> i32 = add_one;
    let f0 = add_one(2i32) * 2;//6
    let f1 = apply(add_one, 2);//6
    let f2 = apply(transform, 2);//6
    println!("f0, f1, f2 的值分别为：{}, {}, {}", f0, f1, f2);

    let closure = |x: i32| x + 1;
    let c0 = closure(2i32) * 2;//6
    let c1 = apply(closure, 2);//6
    let c2 = apply(|x| x + 1, 2);//6
    println!("c0, c1, c2 的值分别为：{}, {}, {}", c0, c1, c2);

    fn factory(x: i32) -> Box<Fn(i32) -> i32> {
        Box::new(move |y| x + y)
    }
    //box_fn相当于是一个闭包：|y| 1 + y
    let box_fn = factory(1i32);
    let b0 = box_fn(2i32) * 2;//6
    let b1 = (*box_fn)(2i32) * 2;//6
    let b2 = (&box_fn)(2i32) * 2;//6
    println!("b0, b1, b2 的值分别为：{}, {}, {}", b0, b1, b2);

    let add_num = &(*box_fn);
    let translate: &Fn(i32) -> i32 = add_num;
    let z0 = add_num(2i32) * 2;//6
    let z1 = apply(add_num, 2);//6
    let z2 = apply(translate, 2);//6
    println!("z0, z1, z2 的值分别为：{}, {}, {}", z0, z1, z2);
}



//方法
//Rust通过impl关键字在struct、enum或者trait对象上实现方法调用语法 (method call syntax)。
//关联函数 (associated function) 的第一个参数通常为self参数，有3种变体：

//self，允许实现者移动和修改对象，对应的闭包特性为FnOnce。
//&self，既不允许实现者移动对象也不允许修改，对应的闭包特性为Fn。
//&mut self，允许实现者修改对象但不允许移动，对应的闭包特性为FnMut。

//不含self参数的关联函数称为静态方法 (static method)。
pub mod method_mod {
    use std::f64::consts::PI;
    pub struct Circle {
        x: f64,
        y: f64,
        radius: f64,
    }

    impl Circle {
        pub fn new(x: f64, y: f64, radius: f64) -> Circle {
            Circle {
                x: x,
                y: y,
                radius: radius,
            }
        }
        pub fn area(&self) -> f64 {
            PI * (self.radius * self.radius)
        }
    }

    pub fn method_test() {
        let c = Circle{
            x: 0f64,
            y: 0f64,
            radius: 2.0,
        };
        println!("c.area is {}", c.area());
        // use associated function and method chaining
        println!("c.area is {}", Circle::new(0.0, 0.0, 2.0).area());
    }
}